/******************************************************************************
 * \brief	链路层通信设备模块的操作
 * \note	File format: UTF-8，中文编码：UTF-8
 * \author	将狼才鲸
 * \date	2023-03-25
 ******************************************************************************/

/*********************************** 头文件 ***********************************/
#include "scp_devs.h"
#include "scp_dev_socket.h"
#include <string.h>	/* memset */
#include <stddef.h>	/* offsetof */

/********************************** 接口函数 **********************************/
/**
 * \brief	从通用设备结构体中获取到具体设备私有的结构体
 * \details	每个具体的通信设备里私有的结构体都不同
 * \param	pdev:	设备结构体
 */
uint8_t *scpdev_pri(scp_dev_t *pdev)
{
	uint8_t *pstruct = (uint8_t *)pdev;
	/* 获取scp_dev_t结构体中priv_data成员的偏移量 */
	size_t size = offsetof(scp_dev_t, priv_data);

	/* 从字节对齐的位置开始取数据 */
	size = ALIGN_TO(size, 16L);

	return (uint8_t *)(pstruct + size);
}

// scp_dev_t *scpdev_from_pri(void *pri)
// {
// }

/**
 * \brief 申请通信需要的数据空间
 * \param	priv_len:	特定通信设备需要的额外数据空间，如sizeof(scpdev_socket_t)
 */
scp_dev_t *scpdev_new(unsigned priv_len)
{
	scp_dev_t *pdev;
	qbuf_t *qbuf;	/* 缓存里面的数据是设备结构体 */


	qbuf = qbuf_alloc(QBUF_GROUP_TMPBUF);
	if (!qbuf)
		return NULL;

	pdev = (scp_dev_t *)(qbuf->addr);
	memset(pdev, 0, sizeof(scp_dev_t) + priv_len);	//48+28

	pdev->qbuf = qbuf;

	return pdev;
}

/**
 * \brief	当前设备结构体是允许的设备
 * \param	pdev:	设备结构体
 * \param	type:	允许的设备类型
 */
bool scpdev_valid(scp_dev_t *pdev, int type)
{
	if (!pdev || !QBUF_ISVALID(pdev->qbuf))
		return false;

	if ((pdev->dev_type & type) == pdev->dev_type)
		return true;

	return false;
}

/**
 * \brief	释放设备句柄
 */
bool scpdev_free(scp_dev_t *pdev)
{
	if (!scpdev_valid(pdev, SCP_DEVTYPE_ANY))
		return false;

	qbuf_free(pdev->qbuf);
	pdev->qbuf = NULL;

	return true;
}

/**
 * \brief	初始化通信设备
 * \param	hwaddr:	如果是多核通信，可以使用内存地址传递数据
 * \param	type:	指定通信设备，如串口、网络、核间通信、进程间通信等
 */
scp_dev_t *scpdevs_init(uint32_t hwaddr, int type)
{
	scp_dev_t *pdev = NULL;

	switch (type)
	{
	case SCP_DEVTYPE_SOCKET:
		/* 初始化网络套接字进程间通信 */
		pdev = scpdev_socket_init(hwaddr, type);
		break;
	case SCP_DEVTYPE_SHM:
	case SCP_DEVTYPE_FIFO:
	case SCP_DEVTYPE_MSGQUEUE_A:
	case SCP_DEVTYPE_MSGQUEUE_B:
		break;
	default:
		break;
	};
	
	return pdev;
}

/**
 * \brief	释放设备缓存
*/
int scpdevs_exit(scp_dev_t *pdev)
{
	int res = -EACCES;

	if (!scpdev_valid(pdev, SCP_DEVTYPE_ANY))
		return res;
	
	switch (pdev->dev_type) {
		case SCP_DEVTYPE_SOCKET:
			/* 释放设备缓存 */
			res = scpdev_socket_stop(pdev);
			break;
		case SCP_DEVTYPE_SHM:
		case SCP_DEVTYPE_FIFO:
		case SCP_DEVTYPE_MSGQUEUE_A:
		case SCP_DEVTYPE_MSGQUEUE_B:
			break;
		//TODO:
	};
	
	return res;
}

/**
 * \brief	准备好设备，清空设备缓存
 */
int scpdevs_start(scp_dev_t *pdev)
{
	int res = -EACCES;

	if (!scpdev_valid(pdev, SCP_DEVTYPE_ANY))	/* 当前设备结构体是允许的设备 */
		return res;

	switch(pdev->dev_type) {
		case SCP_DEVTYPE_SOCKET:
			/* 准备好设备，清空设备缓存 */
			res = scpdev_socket_start(pdev);
			break;
		case SCP_DEVTYPE_SHM:
		case SCP_DEVTYPE_FIFO:
		case SCP_DEVTYPE_MSGQUEUE_A:
		case SCP_DEVTYPE_MSGQUEUE_B:
			break;
		//TODO:
	};

	return res;
}

// int scpdevs_stop(scp_dev_t *pdev)
// {
// }

/**
 * \brief	发送消息
 * \param	seg:	段句柄
 * \param	wmode:	单次消息发送的某个阶段：RWMODE_START、RWMODE_FINISH、RWMODE_REQUEST、RWMODE_RESPOND
 */
int scpdevs_send(segment_t *seg, uint8_t wmode)
{
	int res = -EACCES;
	scp_dev_t *pdev = NULL;	/* 设备句柄 */

	if (!scpseg_valid(seg)
	     || !scpdev_valid(seg->pdev, SCP_DEVTYPE_ANY))
		return -EACCES;

	pdev = seg->pdev;	
	
	switch (pdev->dev_type) {
		case SCP_DEVTYPE_SOCKET:
			res = scpdev_socket_send(seg, wmode);
			break;
		case SCP_DEVTYPE_SHM:
		case SCP_DEVTYPE_FIFO:
		case SCP_DEVTYPE_MSGQUEUE_A:
		case SCP_DEVTYPE_MSGQUEUE_B:
			break;
		//TODO:
	};
	
	return res;
}

/**
 * \brief	接收数据包；有接收队列，从中获取最早到达的包
 * \details	轮询的读消息，一次轮询不一定读到完整的包，可能多次轮询后才能收满包
 * \param	pdev:	设备句柄
 * \param	rmode:	读数据时的步骤：RWMODE_REQUEST...
 * \return	已收完则返回数据包，或者未收完或未收到返回NULL
 */
segment_t *scpdevs_read(scp_dev_t *pdev, uint8_t rmode)
{
	segment_t *seg = NULL;

	if (!scpdev_valid(pdev, SCP_DEVTYPE_ANY))
		return seg;
	
	switch (pdev->dev_type) {
		case SCP_DEVTYPE_SOCKET:
			seg = scpdev_socket_read(pdev, rmode);
			break;
		case SCP_DEVTYPE_SHM:
		case SCP_DEVTYPE_FIFO:
		case SCP_DEVTYPE_MSGQUEUE_A:
		case SCP_DEVTYPE_MSGQUEUE_B:
			break;
		//TODO: 增加其它通信设备
	};
	
	return seg;
}

/*********************************** 文件尾 ***********************************/
